#ifndef _SRC_NET_TCP_SERVER_H_
#define _SRC_NET_TCP_SERVER_H_

#include <atomic>
#include <map>
#include <string_view>

#include "src/base/utils.h"
#include "src/net/tcp_connection.h"

namespace fio66::net
{

class Acceptor;
class EventLoop;
class EventLoopThreadPool;

///
/// TCP server, supports single-threaded and thread-pool models.
///
/// This is an interface class, so don't expose too much details.
class TcpServer
{
 public:
 DISALLOW_COPY_AND_ASSIGN(TcpServer)
  typedef std::function<void(EventLoop*)> ThreadInitCallback;
  enum Option
  {
    kNoReusePort,
    kReusePort,
  };

  //TcpServer(EventLoop* loop, const InetAddress& listenAddr);
  TcpServer(EventLoop* loop,
            const InetAddress& listenAddr,
            const std::string& nameArg,
            Option option = kNoReusePort);
  ~TcpServer();  // force out-line dtor, for std::unique_ptr members.

  std::string_view IpPort() const { return ip_port_; }
  std::string_view Name() const { return name_; }
  EventLoop* GetLoop() const { return loop_; }

  /// Set the number of threads for handling input.
  ///
  /// Always accepts new connection in loop's thread.
  /// Must be called before @c start
  /// @param numThreads
  /// - 0 means all I/O in loop's thread, no thread will created.
  ///   this is the default value.
  /// - 1 means all I/O in another thread.
  /// - N means a thread pool with N threads, new connections
  ///   are assigned on a round-robin basis.
  void SetThreadNum(int numThreads);
  void SetThreadInitCallback(const ThreadInitCallback& cb)
  { thread_init_callback_ = cb; }
  /// valid after calling start()
  std::shared_ptr<EventLoopThreadPool> ThreadPool()
  { return thread_pool_; }

  /// Starts the server if it's not listening.
  ///
  /// It's harmless to call it multiple times.
  /// Thread safe.
  void Start();

  /// Set connection callback.
  /// Not thread safe.
  void SetConnectionCallback(const ConnectionCallback& cb)
  { connection_callback_ = cb; }

  /// Set message callback.
  /// Not thread safe.
  void SetMessageCallback(const MessageCallback& cb)
  { message_callback_ = cb; }

  /// Set write complete callback.
  /// Not thread safe.
  void SetWriteCompleteCallback(const WriteCompleteCallback& cb)
  { write_complete_callback_ = cb; }

 private:
  /// Not thread safe, but in loop
  void NewConnection(int sockfd, const InetAddress& peerAddr);
  /// Thread safe.
  void RemoveConnection(const TcpConnectionPtr& conn);
  /// Not thread safe, but in loop
  void RemoveConnectionInLoop(const TcpConnectionPtr& conn);

  typedef std::map<std::string, TcpConnectionPtr> ConnectionMap;

  EventLoop* loop_;  // the acceptor loop
  const std::string ip_port_;
  const std::string name_;
  std::unique_ptr<Acceptor> acceptor_; // avoid revealing Acceptor
  std::shared_ptr<EventLoopThreadPool> thread_pool_;
  ConnectionCallback connection_callback_;
  MessageCallback message_callback_;
  WriteCompleteCallback write_complete_callback_;
  ThreadInitCallback thread_init_callback_;
  std::atomic_int32_t started_;
  // always in loop thread
  int next_connId_;
  ConnectionMap connections_;
};
  
} // namespace fio66::net



#endif // _SRC_NET_TCP_SERVER_H_
